152442
@@ -20,6 +20,8 @@
import java.util.BitSet;
 
 /**
  * Encoder for unsafe URI characters.
+ * <p/>
+ * A good source for details is <a href="http://en.wikipedia.org/wiki/Url_encode">wikipedia url encode</a> article.
  */
 public final class UnsafeUriCharactersEncoder {
     private static BitSet unsafeCharacters;   
@@ -33,7 +35,7 @@
public final class UnsafeUriCharactersEncoder {
         unsafeCharacters.set('<');
         unsafeCharacters.set('>');
         unsafeCharacters.set('#');
-        // unsafeCharacters.set('%');
+        unsafeCharacters.set('%');
         unsafeCharacters.set('{');
         unsafeCharacters.set('}');
         unsafeCharacters.set('|');
@@ -70,16 +72,32 @@
public final class UnsafeUriCharactersEncoder {
         }
 
         // okay there are some unsafe characters so we do need to encode
+        // see details at: http://en.wikipedia.org/wiki/Url_encode
         StringBuilder sb = new StringBuilder();
-        for (char ch : chars) {
+        for (int i = 0; i < chars.length; i++) {
+            char ch = chars[i];
             if (ch > 0 && ch < 128 && unsafeCharacters.get(ch)) {
-                appendEscape(sb, (byte)ch);
+                // special for % sign as it may be a decimal encoded value
+                if (ch == '%') {
+                    char next = i + 1 < chars.length ? chars[i + 1] : ' ';
+                    char next2 = i + 2 < chars.length ? chars[i + 2] : ' ';
+
+                    if (isHexDigit(next) && isHexDigit(next2)) {
+                        // its already encoded (decimal encoded) so just append as is
+                        sb.append(ch);
+                    } else {
+                        // must escape then, as its an unsafe character
+                        appendEscape(sb, (byte)ch);
+                    }
+                } else {
+                    // must escape then, as its an unsafe character
+                    appendEscape(sb, (byte)ch);
+                }
             } else {
                 sb.append(ch);
             }
         }
         return sb.toString();
-
     }
 
     private static void appendEscape(StringBuilder sb, byte b) {
@@ -88,4 +106,13 @@
public final class UnsafeUriCharactersEncoder {
         sb.append(HEX_DIGITS[(b >> 0) & 0x0f]);
     }
 
+    private static boolean isHexDigit(char ch) {
+        for (char hex : HEX_DIGITS) {
+            if (hex == ch) {
+                return true;
+            }
+        }
+        return false;
+    }
+
 }
